$TITLE ('RTX-51 SEND MESSAGE/SIGNAL/TOKEN SYSTEM CALLS')
$SYMBOLS
$NOXREF
$NOCOND
$NOMOD51
$NORB
$PAGELENGTH(80) PAGEWIDTH(110)
;************************************************************************
;*									*
;*    R T X - 5 1  :   SEND MESSAGE, SIGNAL AND TOKEN SYSTEM CALLS      *
;*							     		*
;*----------------------------------------------------------------------*
;*                                                                      *
;*    Filename     :   RTXSEND.A51                                      *
;*    Language     :   Keil A-51                                        *
;*    Dev. system  :   Keil uVision2                                    *
;*    Targetsystem :   Any system based upon 8051 up                    *
;*                                                                      *
;*    Purpose      :   Implements the system calls os_send_message,     *
;*                     os_send_signal and os_send_token.                *
;*								     	*
;*----------------------------------------------------------------------*
;* Rev. |  Released   | Programmer    | Comments                        *
;*----------------------------------------------------------------------*
;* 0.1  |  16.1.1991  | E. Glatz      | Changes for V3.20               *
;* 0.2  |   8.3.1991  | Th. Fischler  | C-51 parameter passing          *
;*      |   8.5.1991  |               | P2-addressing eliminated,       *
;*      |             |               | V4.0 context adaptions          *
;*      |   6.6.1991  | Th. Fischler  | send_signal optimized           *
;*      |  24.6.1991  |               | malbox-nbr tested               *
;*      |             |               | Disable all interrupts while    *
;*      |             |               | mailbox access                  *
;*      |  4.06.1992  |               | RTXINS.INC converted to proc.   *
;* 5.00 | 11.10.1994  | E. Glatz      | os_send_token added             *
;* 7.00 | 13.11.2001  | T. Mueller    | Release 7.00                    *
;************************************************************************
;*    Copyright 1991 .. 2001 METTLER  &  FUCHS  AG,  CH-8953 Dietikon   *
;************************************************************************

$INCLUDE (RTXDEBUG.INC)
$INCLUDE (RTXIMASK.INC)

;*----------------------------------------------------------------------*
;*	I M P O R T S
;*----------------------------------------------------------------------*

$INCLUDE (RTXCONST.INC)
$INCLUDE (RTXEXTRN.INC)

;	FROM RTXDISP
EXTRN   CODE    (?RTX_REDISPATCH)

;	FROM RTXBLOCK
EXTRN   CODE    (?RTX_NDBLOCK, ?RTX_DBLOCK)

;       FROM RTXQUOP
EXTRN   CODE    (?RTX_TMO_DEQUEUE, ?RTX_INTSIG_DEQUEUE)
EXTRN   CODE    (?RTX_MSG_DEQUEUE, ?RTX_SEM_DEQUEUE)
EXTRN   CODE    (?RTX_NFL_ENQUEUE, ?RTX_TMO_ENQUEUE)

;        FROM RTXINS
EXTRN    CODE  (?RTX_INSERT_RDY_PRIO)


;*----------------------------------------------------------------------*
;*	E X P O R T S
;*----------------------------------------------------------------------*

PUBLIC  ?RTX_NFL_NDEVENT, ?RTX_NFL_DEVENT

PUBLIC  _os_send_message
PUBLIC  _os_send_signal
PUBLIC  _os_send_token


;*----------------------------------------------------------------------*
;*	P R O C E D U R E S
;*----------------------------------------------------------------------*

;*----------------------------------------------------------------------*
;*      O S _ S E N D _ M E S S A G E
;*----------------------------------------------------------------------*
;*      System call for sending a message to a mailbox.
;*----------------------------------------------------------------------*
;*      Input:  (C-51 conventions)
;*      -----
;*               - R3 : timeout value
;*                      = 0          --> no timeout
;*                      = 1..254     --> timeout [no of system ticks]
;*                      = 255        --> wait forever,task not in-
;*			                 serted in delay list
;*               - R7 : mailbox no
;*               - R4 : HIGH (message)
;*               - R5 : LOW  (message)
;*
;*      Output:  - Returns execution status in R7 (OK or NOT_OK)
;*      ------
;*
;*----------------------------------------------------------------------*
;*      Internal Register Usage :   R2 : timeout value
;*      -----------------------     R4 : mailbox no
;*                                  R5 : HIGH (message)
;*                                  R6 : LOW (message)
;*
;*                                  R3 : parameter to NDBLOCK
;*                                  R0 : temporary storage
;*----------------------------------------------------------------------*

?RTX?_os_send_message?RTXSEND  SEGMENT CODE
                                  RSEG    ?RTX?_os_send_message?RTXSEND

MOVR            MACRO   REG1, REG2
;; stores REG2 in REG1 via A
                   MOV  A, REG2
                   MOV  REG1, A
                ENDM

_os_send_message:
               DBG_SYS_ENTRY
               RTX_EXCLUDE_INT
               ; Copy the C-51 parameters to the used registers
               ; (this Version uses the original V3.20 Register-Layout
               ; in this function)
               MOVR  R2, R3                     ; timeout
               MOVR  R6, R5                     ; LOW(message)
               MOVR  R5, R4                     ; HIGH(message)
               MOVR  R4, R7                     ; mailbox no
               SETB  ?RTX_SUPERVISOR_MODE       ; Supervisor_mode := on
               RTX_ALLOW_DRV_INT

               ; Check the mailbox-parameter
               MOV   A, R4
               SETB  C
               SUBB  A, #7H
               JC    SECOND_TRY
               ; input parameter not ok
               MOV   R7, #NOT_OK
               RTX_EXCLUDE_INT
               JMP   END_SEND

SECOND_TRY:    MOV   A, R4                      ; Get mailbox no param.
               SWAP  A
               RR    A                          ; ACC := 8 * mailbox no
               ADD   A, #LOW(?RTX_MBX_CONTROL_BASE)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_MBX_CONTROL_BASE) ; DPTR --> ?RTX_MBX#_COUNT

;
;       Depending on mbx count values one of the following three actions
;       is performed:
;       a) MBX#_COUNT < 0 (tasks are waiting for messages, MBX#_COUNT is 2's 
;          complement of waiting task count):
;          Pass message directly to first waiting task !
;       b) MBX#_COUNT = 8 (no tasks wait for messages, message list contains
;          8 messages, i.e. is full):
;          Enqueue task in non full wait list !
;       c) MBX#_COUNT = 8 (16 tasks are waiting for non-full message list,
;          message list contains 8 messages, i.e. is full):
;          Return error status !
;       d) MBX#_COUNT = 0..7 (no tasks wait for messages, message list is not
;          full):
;          Write message to mailbox message list !
;
               RTX_EXCLUDE_INT
               GLOBAL_INT_DISABLE
               MOVX  A, @DPTR                   ; Get MBX#_COUNT
               ; Check if any tasks are waiting for messages
               JB    ACC.7, TASKS_WAIT          ; Jump if tasks wait (count<0)
                                                ; Check if message list is
NO_TASKS_WAIT: JNB   ACC.3, NOT_FULL            ; full (max. 8 messages)
               GLOBAL_INT_ENABLE
               JMP   MSG_FULL                   ; Yes: enqueue task for non
                                                ; full wait
;
;       No tasks wait for messages and message list is not full
;       (MBX#_COUNT = 0..7)
;
NOT_FULL:	                                
               INC   A                          ; MBX#_COUNT = MBX#_COUNT + 1
               MOVX  @DPTR, A                   ; Store new MBX#_COUNT value
               INC   DPL
               INC   DPL
               INC   DPL                        ; DPTR --> MBX#_LAST

               MOVX  A, @DPTR                   ; MBX#_LAST = MBX#_LAST + 1
               INC   A
               ANL   A, #0EFH

               MOV   R0, DPL                    ; save DPL
               MOV   DPH, #HIGH(?RTX_MBX_PAGE)
               MOV   DPL, A                     ; DPTR: FIFO-Pointer to last
                                                ; el. + 1 of MBX#_LIST
               MOV   A, R5                      ; Insert high (R5) and low (R6)
               MOVX  @DPTR, A                   ; byte of msg.(high byte first)
					        ; in specified mailbox.
               MOV   A, DPL                     ; Increment FIFO-pointer
               INC   A
               ANL   A, #0EFH
               MOV   DPH, #HIGH(?RTX_MBX_CONTROL_BASE)
               MOV   DPL, R0
               MOVX  @DPTR, A                   ; Store new value of LAST-ptr
                                                ; (Points always to LAST
                                                ;  element)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_MBX_PAGE)
               MOV   A, R6
               MOVX  @DPTR, A
               GLOBAL_INT_ENABLE

               MOV   R7, #OK                    ; Set up return status

END_SEND:      ; exit sequence: task interrupts must be disabled here !
               ;
               JB    ?RTX_REQ_REDISPATCH, RED   ; Redispatch requested ?
					        ; No:
               CLR   ?RTX_SUPERVISOR_MODE       ; supervisor_mode := OFF
               DBG_SYS_EXIT
               RTX_ALLOW_INT
               RET

RED:           CLR   ?RTX_FULL_CONTEXT
               JMP   ?RTX_REDISPATCH

;       At least one task is waiting for a message: do not write message to
;       mailbox list but pass it directly to waiting task.
;       (MBX#_COUNT < 0)
;       
TASKS_WAIT:                                     ; Dequeue first waiting task
                                                ; from mailbox task list
               INC   A
               MOVX  @DPTR, A                   ; MBX#_COUNT=MBX#_COUNT+1
               INC   DPL                        ; (dec. 2's compl. means incr.)
               INC   DPL                        ; DPTR --> MBX#_FIRST
               MOVX  A, @DPTR
               MOV   B, A                       ; temp. save MBX#_FIRST
               INC   A
               ANL   A, #0EFH
               MOVX  @DPTR, A                   ; MBX#_FIRST=MBX#_FIRST+1

               MOV   DPH, #HIGH(?RTX_MBX_PAGE)
               MOV   DPL, B                     ; (DPTR) --> task FIFO
               MOVX  A, @DPTR                   ; Read first task id from list
               MOV   ?RTX_TMP0, A               ; and store in ?RTX_TMP0
               GLOBAL_INT_ENABLE

               ; Set up pointer to state_table[task no]
               ANL   A, #01FH
               RL    A
               RL    A
               ADD   A, #LOW(?RTX_STATE_TABLE)
               MOV   DPH, #HIGH(?RTX_STATE_TABLE)
               MOV   DPL, A                     ; DPTR->state_table[task no]
               MOVX  A, @DPTR
               ANL   A, #0FEH                   ; Reset msg wait bit in state
               MOVX  @DPTR, A

               ; Dequeue task from any wait list it could be contained in
               POP   ?RTX_TMP1                  ; Make free 2 bytes of stack
               POP   ?RTX_TMP2                  ; for subroutine call
                                                ; DPTR->state_table[task no]
                                                ; ?RTX_TMP0 contains task id
               CALL ?RTX_TMO_DEQUEUE
                                                ; DPTR, ?RTX_TMP0 preserved
               CALL ?RTX_INTSIG_DEQUEUE

               PUSH  ?RTX_TMP2                  ; Restore return address
               PUSH  ?RTX_TMP1                  ; to stack

               ; Return status and message have to be stored in this
               ; tasks context
               MOV   A, ?RTX_TMP0               ; Fast task context must be
               JB    ACC.4, DRIVER_CONTEXT      ; handled differently

               ; Store in standard task (=non driver task) context
               ANL   A, #0FH                    ; ACC := standard task nr.
               MOV   B, A
               MOV   A, #LOW(?RTX_KNTXT_PTR_TABLE)
               ADD   A, B
               ADD   A, B
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_KNTXT_PTR_TABLE) ; DPTR -> tasks context
               MOVX  A, @DPTR
               MOV   B, A
               INC   DPL
               MOVX  A, @DPTR
               MOV   DPH, B
               MOV   DPL, A

               MOV   A, #MSG_EVENT
               INC   DPL
               MOVX  @DPTR, A                   ; Store return status to r7

               ; Set up pointer to message return location (it is
               ; contained in context R5/R6)
               INC   DPL                        ; DPTR --> context (R6)
               MOVX  A, @DPTR                   ; Get R6
               MOV   R0, A
               INC   DPTR                       ; DPTR --> context (R5)
               MOVX  A, @DPTR                   ; Get R5
               MOV   DPH, A
               MOV   DPL, R0                    ; (DPTR)-->msg return location
               JMP   STORE_MSG

               ; Store in fast task (=driver task) context
DRIVER_CONTEXT:
               JB    ACC.1, DRIVER3
               JB    ACC.0, DRIVER2

DRIVER1:       MOV   RB1R7, #MSG_EVENT          ; Store return status
               ; Set up pointer to message
               MOV   DPH, RB1R5                 ; return location (it is con-
               MOV   DPL, RB1R6                 ; tained in context R5/R6)
               JMP   STORE_MSG

DRIVER2:       MOV   RB2R7, #MSG_EVENT          ; Store return status
               ; Set up pointer to message
               MOV   DPH, RB2R5                 ; return location (it is con-
               MOV   DPL, RB2R6                 ; tained in context R5/R6)
               JMP   STORE_MSG

DRIVER3:       MOV   RB3R7, #MSG_EVENT          ; Store return status
               ; Set up pointer to message
               MOV   DPH, RB3R5                 ; return location (it is con-
               MOV   DPL, RB3R6                 ; tained in context R5/R6)

STORE_MSG:	                                ; Now store message at return
                                                ; location in external RAM
               MOV   A, R5
               MOVX  @DPTR, A                   ; Store HIGH(MESSAGE)
               INC   DPTR
               MOV   A, R6
               MOVX  @DPTR, A                   ; Store LOW(MESSAGE)

               MOV   A, ?RTX_TMP0               ; Restore dest. task id.

COMMON:                                         ; Requires: ACC holds task id
               ; Insert task in ready list
               POP   ?RTX_TMP1                  ; Make free 2 bytes of stack
               POP   ?RTX_TMP2                  ; for subroutine call
               CALL  ?RTX_INSERT_RDY_PRIO
               PUSH  ?RTX_TMP2                  ; Restore return address
               PUSH  ?RTX_TMP1                  ; to stack

               MOV   R7, #OK                    ; Status := #OK
               CLR   ?RTX_FULL_CONTEXT          ; Resign reduced context
               ; We must redispatch because we made a task ready
               JMP   ?RTX_REDISPATCH

TMO_EXIT:	
               MOV   R7, #NOT_OK                ; Status = tmo event (on non
               JMP   END_SEND                   ; full wait)
;
;               Prepare error return
;
NFL_FULL:	
               PUSH  ?RTX_TMP2                  ; Restore return address
               PUSH  ?RTX_TMP1                  ; to stack
               MOV   R7, #NOT_OK                ; Status = nf list full
               JMP   END_SEND

;
;	No tasks wait for messages and message list is full (MBX#_COUNT = 8). 
;       Task must wait writing a message to mailbox message list until at 
;       least one message is read out.
;       
;
MSG_FULL:      ; No enqueue for zero timeout
               MOV   A, R2
               JZ    TMO_EXIT

               POP   ?RTX_TMP1                  ; Make free 2 bytes of stack
               POP   ?RTX_TMP2                  ; for subroutine call
                
               CALL  ?RTX_NFL_ENQUEUE
               JNZ   NFL_FULL

               CALL  ?RTX_TMO_ENQUEUE
                
               PUSH  ?RTX_TMP2                  ; Restore return address
               PUSH  ?RTX_TMP1                  ; to stack

                                                ; Block task
               JB    ?RTX_RUNNING_TID.4, DRBLOCK
               RTX_ALLOW_DRV_INT

               ; Block standard tasks. Request reduced resign with
               ; save of R6/R5/R4
               MOV   R3, #1
               JMP   ?RTX_NDBLOCK

               ; Return from non full wait, if context(R7)=NFL_EVENT
?RTX_NFL_NDEVENT:
                                                ; Try again to write to mail-
               JMP   SECOND_TRY                 ; box message list
                                        
DRBLOCK:       ; Block fast tasks
               JMP   ?RTX_DBLOCK                ; Params are save in reg. bank
                                                ; Return from non full wait,
                                                ; if context(R7)=NFL_EVENT
?RTX_NFL_DEVENT:
                                                ; Try again to write to mail-
               JMP   SECOND_TRY                 ; box message list
                                                



;*----------------------------------------------------------------------*
;*      O S _ S E N D _ S I G N A L
;*----------------------------------------------------------------------*
;*      System call for sending a signal to a task.
;*----------------------------------------------------------------------*
;*      Input:   - R7 : destination task number
;*
;*      Output:  - Returns execution status in R7 (OK, NOT_OK)
;*
;*----------------------------------------------------------------------*

?RTX?_os_send_signal?RTXSEND  SEGMENT CODE
                                 RSEG    ?RTX?_os_send_signal?RTXSEND

_os_send_signal:
               DBG_SYS_ENTRY
               RTX_EXCLUDE_INT
               SETB  ?RTX_SUPERVISOR_MODE       ; Supervisor_mode := on
               ; Check task-number
               MOV   A, R7
               SETB  C
               SUBB  A, #?RTX_MAXTASKN
               JC    EVAL_INTERNAL_NUM
               ; Number is greater than the maximum used task-number
               MOV   R7, #NOT_OK
               JMP   END_SEND

EVAL_INTERNAL_NUM:
               ; Evaluate the internal Task-Number
               MOV   DPH, #HIGH(?RTX_USER_NUM_TABLE)
               MOV   A, #LOW(?RTX_USER_NUM_TABLE)
               ADD   A, R7
               MOV   DPL, A
               ; DPTR -> user_num_table[user_num]
               MOVX  A, @DPTR
               CJNE  A, #NO_TASK, TASK_FOUND
               MOV   R7, #NOT_OK
               JMP   END_SEND                   ; not a valid task


TASK_FOUND:    MOV   R7, A                      ; internal task-num in R7
               MOV   DPH, #HIGH(?RTX_TID_TABLE)
               MOV   A, #LOW(?RTX_TID_TABLE)
               ADD   A, R7
               MOV   DPL, A                     ; DPTR-> TID_TABLE[task_num]
               MOVX  A, @DPTR

               ;  Set up ptr to task state of signal receiving task
               MOV   R6, A                      ; save TID of receiving task
               MOV   A, R7
               RL    A
               RL    A
               ADD   A, #LOW (?RTX_STATE_TABLE)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_STATE_TABLE)

               MOVX  A, @DPTR
;
;     Depending on the state of the signal receiving task one of the two
;     following actions is performed:
;     a) task waits for signal: task is made ready, a redispatch is initiated
;     b) task does not wait for signal: signal is stored as request in this
;        tasks first state byte, control is returned to caller
;
                                                ; Check if destination task
               JB    ACC.2, WAITS               ; is waiting for signal
                                                ; Check if already a signal was
                                                ; sent to this task, which it
               JB    ACC.7, PENDING             ; did not yet receive
;
;       Signal receiving task does not wait for it.
;
NO_PENDING_REQ:
               ORL   A, #80H                    ; Set signal request bit.
               MOVX  @DPTR, A                   ; Store it in first state byte

               MOV   R7, #OK                    ; task was not waiting
               JMP   END_SEND

PENDING:       MOV   R7, #NOT_OK                ; Status = task had already
                                                ; a pending signal request
               JMP   END_SEND
;
;       Signal receiving task waits for it.
;
WAITS:         MOV   ?RTX_TMP0, R6

               POP   ?RTX_TMP1                  ; Make free 2 bytes of stack
               POP   ?RTX_TMP2                  ; for subroutine call
                                                ; DPTR->state_table[task no]
                                                ; ?RTX_TMP0 contains task id
               CALL  ?RTX_TMO_DEQUEUE
                                                ; DPTR, ?RTX_TMP0 preserved
               CALL  ?RTX_INTSIG_DEQUEUE
                                                ; DPTR, ?RTX_TMP0 preserved
               CALL  ?RTX_MSG_DEQUEUE           
               JZ    MSGDEQDONE                 ; Eval ret code if deq done
                                                ; DPTR preserved if no deq done
               CALL  ?RTX_SEM_DEQUEUE           ; ?RTX_TMP0 preserved
MSGDEQDONE:
               PUSH  ?RTX_TMP2                  ; Restore return address
               PUSH  ?RTX_TMP1                  ; to stack

DEQU_DONE:	                                ; Store return status in con-
                                                ; text of signal receiving task
               MOV   A, R6
                                                ; Fast and standard task context
               JB    ACC.4, DRIV_CONTEXT        ; must be handled differently

               ; Store in standard task context
               MOV   B, R7                      ; B = internal Task-number
               MOV   A, #LOW(?RTX_KNTXT_PTR_TABLE)
               ADD   A, B
               ADD   A, B
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_KNTXT_PTR_TABLE)
               MOVX  A, @DPTR
               MOV   R0, A
               INC   DPL
               MOVX  A, @DPTR
               MOV   DPH, R0
               MOV   DPL, A                     ; DPTR -> Task context
               MOV   A, #SIG_EVENT
               INC   DPL
               MOVX  @DPTR, A                   ; Store return status to r7

               ; Insert task in ready list and prepare function return
               MOV   A, R6
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of OS_SEND_MESSAGE)

                                                ; Store in standard task context
DRIV_CONTEXT:  JB    ACC.1, DRIV3
               JB    ACC.0, DRIV2

               MOV   RB1R7, #SIG_EVENT          ; Store return status
               ; Insert task in ready list and prepare function return
               MOV   A, R6
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of RTX_SEND_MESSAGE)

DRIV2:         MOV   RB2R7, #SIG_EVENT
               ; Insert task in ready list and prepare function return
               MOV   A, R6
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of RTX_SEND_MESSAGE)

DRIV3:         MOV   RB3R7, #SIG_EVENT
               ; Insert task in ready list and prepare function return
               MOV   A, R6
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of RTX_SEND_MESSAGE)



;*----------------------------------------------------------------------*
;*      O S _ S E N D _ T O K E N
;*----------------------------------------------------------------------*
;*      System call for sending a token to a semaphore.
;*----------------------------------------------------------------------*
;*      Input:   - R7 : semaphore number [8..15]
;*
;*      Output:  - Returns execution status in R7 (OK, NOT_OK)
;*
;*----------------------------------------------------------------------*

?RTX?_os_send_token?RTXSEND  SEGMENT CODE
                                 RSEG    ?RTX?_os_send_token?RTXSEND

_os_send_token:
               DBG_SYS_ENTRY
               RTX_EXCLUDE_INT
               SETB  ?RTX_SUPERVISOR_MODE       ; Supervisor_mode := on
               ; Check semaphore-number
               MOV   A, R7
               JNB   ACC.3, SEM_NOTOK
               ANL   A, #0F0H 
               JZ    SEM_OK
SEM_NOTOK:     ; Number is outside of 8..15
               MOV   R7, #NOT_OK
               JMP   END_SEND
SEM_OK:
;
;     Depending on the state of the semaphore one of the three
;     following actions is performed:
;     (1) one or more task wait for token: first task is made ready, 
;                                          a redispatch is initiated
;     (2) token flag reset, no task waits: set token flag
;     (3) token flag is set:               return with NOT_OK
;
               ; Check if task(s) wait
               MOV   A, R7
               ANL   A, #007H
               SWAP  A                          ; get internal semaphore                          
               RR    A                          ; number * 8
               ADD   A, #LOW(?RTX_MBX_CONTROL_BASE)
               ADD   A, #7                      ; Move ptr to SEM#_LAST
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_MBX_CONTROL_BASE)
               MOVX  A, @DPTR                   ; Get SEM#_LAST
               MOV   B, A
               DEC   DPL                
               MOVX  A, @DPTR                   ; Get SEM#_FIRST
               CJNE  A, B, TASKS_WAIT2          ; Test if (1) or (2)/(3)
NO_TASKS_WAIT2:
               MOV   A, R7                      
               ANL   A, #007H                   ; get internal semaphore no
               ADD   A, #LOW(?RTX_SEM_TOKENS)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_SEM_TOKENS)
               MOVX  A, @DPTR
               JZ    TOKN_OK
               ; Token flag set error
               MOV   R7, #NOT_OK                ; It is (3)
               JMP   END_SEND
TOKN_OK:
               ; Set token flag
               MOV   A, #1                      ; It is (2)
               MOVX  @DPTR, A
               ; All done
               MOV   R7, #OK
               JMP   END_SEND                   
TASKS_WAIT2:                                    ; It is (1)
               MOV   B, A                       ; Dequeue first waiting task
               ANL   A, #00FH                   ; Store old SEM#_FIRST temporarily
               CJNE  A, #00FH, NO_WRAP2
               MOV   A, B                       ; (a) rewind ptr
               ANL   A, #0F0H
               SJMP  INC_DONE2
NO_WRAP2:      MOV   A, B                       ; (b) incr. ptr
               INC   A
INC_DONE2:     MOVX  @DPTR, A                   ; Store new SEM#_FIRST
               MOV   DPL, B                     ; get back old SEM#_FIRST
               MOV   DPH, #HIGH(?RTX_SEM_PAGE)
               MOVX  A, @DPTR                   ; Read first task from list and
               MOV   ?RTX_TMP0, A               ; store  in ?RTX_TMP0

               ; Set up pointer to state_table[task no]
               ANL   A, #01FH
               RL    A
               RL    A
               ADD   A, #LOW(?RTX_STATE_TABLE+1)
               MOV   DPL, A                     
               MOV   DPH, #HIGH(?RTX_STATE_TABLE) ; DPTR->state_table[task no]+1
               MOVX  A, @DPTR
               ANL   A, #07FH                   ; Reset WN bit in state
               MOVX  @DPTR, A
               DEC   DPL
               MOVX  A, @DPTR
               ANL   A, #0FEH                   ; Reset WM bit in state
               MOVX  @DPTR, A

               POP   ?RTX_TMP1                  ; Make free 2 bytes of stack
               POP   ?RTX_TMP2                  ; for subroutine call
                                                ; DPTR->state_table[task no]
                                                ; ?RTX_TMP0 contains task id
               CALL  ?RTX_TMO_DEQUEUE
                                                ; DPTR, ?RTX_TMP0 preserved
               CALL  ?RTX_INTSIG_DEQUEUE

               PUSH  ?RTX_TMP2                  ; Restore return address
               PUSH  ?RTX_TMP1                  ; to stack

DEQU_DONE2:	                                ; Store return status in con-
                                                ; text of token receiving task
               MOV   A, ?RTX_TMP0
                                                ; Fast task context must be
               JB    ACC.4, DRIVER_CONTEXT2     ; handled differently

               ; Store in non driver context
               ANL   A, #0FH                    ; ACC := standard task nr.
               MOV   B, A
               MOV   A, #LOW(?RTX_KNTXT_PTR_TABLE)
               ADD   A, B
               ADD   A, B
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_KNTXT_PTR_TABLE) ; DPTR -> tasks context
               MOVX  A, @DPTR
               MOV   B, A
               INC   DPL
               MOVX  A, @DPTR
               MOV   DPH, B
               MOV   DPL, A

               MOV   A, #SEM_EVENT
               INC   DPL
               MOVX  @DPTR, A                   ; Store return status to r7

               ; Insert task in ready list and prepare function return
               MOV   A, ?RTX_TMP0               ; Restore dest. task id.
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of OS_SEND_MESSAGE)

               ; Store in fast task context
DRIVER_CONTEXT2:
               JB    ACC.1, DRIVER32
               JB    ACC.0, DRIVER22

DRIVER12:      MOV   RB1R7, #SEM_EVENT          ; Store return status
               ; Insert task in ready list and prepare function return
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of OS_SEND_MESSAGE)

DRIVER22:      MOV   RB2R7, #SEM_EVENT          ; Store return status
               ; Insert task in ready list and prepare function return
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of OS_SEND_MESSAGE)

DRIVER32:      MOV   RB3R7, #SEM_EVENT          ; Store return status
               ; Insert task in ready list and prepare function return
                                                ; ACC holds task id
               JMP   COMMON                     ; (use code of OS_SEND_MESSAGE)


;
;   END OF MODULE
;
	END
